<template>
  <div class="upload-center-wrapper">
    <div class="upload-card">
      <!-- 连接状态指示器 -->
      <div class="connection-status" :class="connectionStatus">
        <span v-if="connectionStatus === 'connected'">🟢 已连接</span>
        <span v-else-if="connectionStatus === 'connecting'">🟠 连接中...</span>
        <span v-else>🔴 未连接</span>
      </div>

      <!-- 录音控制按钮和等待动画 -->
      <div class="center-row">
        <button
          @click="toggleRecording"
          class="submit-button"
          :class="{ loading: isRecording }"
          :disabled="isLoading || connectionStatus !== 'connected' || isConverting"
        >
          <template v-if="!isRecording && !isConverting">🎤 开始录音</template>
          <template v-else-if="isRecording && !isConverting">
            <svg class="spinner" viewBox="0 0 50 50">
              <circle cx="25" cy="25" r="20" fill="none" stroke="#fff" stroke-width="5" stroke-linecap="round" stroke-dasharray="90 150"/>
            </svg>
            <span>录音中... 已录制：{{ recordElapsed }} 秒</span>
          </template>
          <template v-else-if="isConverting">
            <svg class="spinner" viewBox="0 0 50 50">
              <circle cx="25" cy="25" r="20" fill="none" stroke="#fff" stroke-width="5" stroke-linecap="round" stroke-dasharray="90 150"/>
            </svg>
            <span>正在转换音频格式... {{ convertProgress }}%</span>
          </template>
        </button>
      </div>

      <!-- 状态提示 -->
      <div class="status-message" v-if="errorMessage">
        <p class="error">{{ errorMessage }}</p>
      </div>
      <div class="status-message" v-else-if="isLoading">
        <p class="loading">正在初始化语音引擎...</p>
      </div>

      <!-- 音频可视化，仅录音中展示 -->
      <div v-if="isRecording" class="visualizer">
        <canvas ref="canvas" width="300" height="100"></canvas>
      </div>
      <!-- 录音结束后展示录音时长 -->
      <div v-if="!isRecording && lastRecordDuration > 0" class="center-row" style="margin-bottom: 0.5rem; color: #64748b; font-size: 1rem;">
        本次录音时长：{{ lastRecordDuration }} 秒
      </div>

      <!-- 识别和翻译结果并排 -->
      <div v-if="finalResult || translatedText" class="result-container">
        <div class="result-header center-row">
          <h3>识别结果</h3>
        </div>
        <div class="result-details-pair">
          <div class="detail-block">
            <div class="detail-label">原文</div>
            <div class="detail-value scrollable-text">{{ finalResult || '暂无文本' }}</div>
          </div>
          <div class="detail-block">
            <div class="detail-label">翻译</div>
            <div class="translated-value scrollable-text">{{ translatedText || '（请点击翻译）' }}</div>
          </div>
        </div>
        <!-- 目标语言选择 -->
        <div class="center-row" style="margin-top: 1rem;">
          <label style="margin-right: 0.5rem; color: #64748b;">目标语言：</label>
          <select v-model="targetLang" style="padding: 0.3rem 1rem; border-radius: 6px; border: 1px solid #e2e8f0;">
            <option v-for="opt in langOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</option>
          </select>
        </div>
        <div class="center-row" style="margin-top: 1rem;">
          <button
            class="translate-button"
            :disabled="isTranslating || !finalResult"
            @click="translateResult"
          >
            <span v-if="!isTranslating">翻译</span>
            <span v-else>翻译中...</span>
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { ref, onUnmounted } from 'vue'
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'
import axios from 'axios'

// 支持的目标语言列表
const langOptions = [
  { label: '英文', value: 'en' },
  { label: '中文', value: 'zh' },
  { label: '日文', value: 'jp' },
  { label: '韩文', value: 'kor' },
  { label: '法文', value: 'fra' },
  { label: '德文', value: 'de' },
  { label: '西班牙文', value: 'spa' },
]
const targetLang = ref('en')

export default {
  setup() {
    // 核心状态管理
    const isRecording = ref(false)
    const isLoading = ref(true)
    const isConverting = ref(false)
    const errorMessage = ref('')
    const convertProgress = ref(0)
    const connectionStatus = ref('disconnected')
    const finalResult = ref('')
    const translatedText = ref('')
    const isTranslating = ref(false)
    const recordElapsed = ref(0)
    const lastRecordDuration = ref(0)
    let recordTimer = null

    // WebSocket相关
    const ws = ref(null)
    const reconnectAttempts = ref(0)
    const maxReconnectAttempts = 5

    // 音频处理相关
    const mediaRecorder = ref(null)
    const audioChunks = ref([])
    const canvas = ref(null)
    const ffmpeg = createFFmpeg({
      log: true,
      progress: ({ ratio }) => {
        convertProgress.value = Math.round(ratio * 100)
      }
    })

    // 音频可视化
    let audioContext = null
    let analyser = null
    let animationFrame = null

    // 初始化WebSocket连接
    const initWebSocket = () => {
      if (ws.value) {
        ws.value.close()
      }

      connectionStatus.value = 'connecting'
      ws.value = new WebSocket('ws://localhost:8000/ws/stream-recognize')

      ws.value.onopen = () => {
        connectionStatus.value = 'connected'
        reconnectAttempts.value = 0
        isLoading.value = false
        console.log('语音引擎连接成功')
      }

      ws.value.onmessage = (event) => {
        try {
          const data = JSON.parse(event.data)
          if (data.text) {
            finalResult.value = data.text
          }
        } catch (error) {
          console.error('消息解析失败:', error)
        }
      }

      ws.value.onerror = (error) => {
        console.error('WebSocket错误:', error)
        connectionStatus.value = 'disconnected'
      }

      ws.value.onclose = () => {
        connectionStatus.value = 'disconnected'
        if (reconnectAttempts.value < maxReconnectAttempts) {
          setTimeout(() => {
            reconnectAttempts.value++
            initWebSocket()
          }, Math.min(1000 * reconnectAttempts.value, 5000))
        }
      }
    }

    // 音频可视化初始化
    const initVisualizer = (stream) => {
      try {
        audioContext = new (window.AudioContext || window.webkitAudioContext)()
        analyser = audioContext.createAnalyser()
        const source = audioContext.createMediaStreamSource(stream)
        source.connect(analyser)
        analyser.fftSize = 256
        drawVisualizer()
      } catch (error) {
        console.warn('音频可视化初始化失败:', error)
      }
    }

    // 绘制音频波形
    const drawVisualizer = () => {
      if (!analyser || !canvas.value) return

      const ctx = canvas.value.getContext('2d')
      const bufferLength = analyser.frequencyBinCount
      const dataArray = new Uint8Array(bufferLength)

      const draw = () => {
        animationFrame = requestAnimationFrame(draw)
        analyser.getByteFrequencyData(dataArray)
        
        // 背景色调整为卡片主题色
        ctx.fillStyle = '#f8fafc' // 浅灰蓝色，与卡片背景一致
        ctx.fillRect(0, 0, canvas.value.width, canvas.value.height)
        const barWidth = (canvas.value.width / bufferLength) * 2.5
        let x = 0

        dataArray.forEach(value => {
          const barHeight = value / 2
          // 主色调高亮（如Upload主色 #4361ee 渐变到 #22c55e）
          const percent = barHeight / 128
          const r = Math.round(67 + (34-67)*percent) // 67->34
          const g = Math.round(97 + (197-97)*percent) // 97->197
          const b = Math.round(238 + (94-238)*percent) // 238->94
          ctx.fillStyle = `rgb(${r},${g},${b})`
          ctx.fillRect(x, canvas.value.height - barHeight, barWidth, barHeight)
          x += barWidth + 1
        })
      }

      draw()
    }

    // 音频格式转换
    const convertToWav = async (webmBlob) => {
      try {
        if (!ffmpeg.isLoaded()) {
          await ffmpeg.load()
        }

        ffmpeg.FS('writeFile', 'input.webm', await fetchFile(webmBlob))
        
        await ffmpeg.run(
          '-i', 'input.webm',
          '-c:a', 'pcm_s16le',
          '-ar', '16000',
          '-ac', '1',
          'output.wav'
        )

        const data = ffmpeg.FS('readFile', 'output.wav')
        return new Blob([data.buffer], { type: 'audio/wav' })
      } catch (error) {
        throw new Error(`音频转换失败: ${error.message}`)
      }
    }

    // 录音控制
    const toggleRecording = async () => {
      if (!isRecording.value) {
        try {
          const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
          initVisualizer(stream)
          
          mediaRecorder.value = new MediaRecorder(stream, {
            mimeType: 'audio/webm;codecs=opus',
            audioBitsPerSecond: 16000
          })

          mediaRecorder.value.ondataavailable = (e) => {
            if (e.data.size > 0) audioChunks.value.push(e.data)
          }

          mediaRecorder.value.onstop = async () => {
            try {
              isConverting.value = true
              stopRecordTimer()
              lastRecordDuration.value = recordElapsed.value
              const webmBlob = new Blob(audioChunks.value, { type: 'audio/webm' })
              const wavBlob = await convertToWav(webmBlob)
              
              if (ws.value?.readyState === WebSocket.OPEN) {
                ws.value.send(await wavBlob.arrayBuffer())
              } else {
                throw new Error('语音引擎连接已断开')
              }
            } catch (error) {
              errorMessage.value = `发送失败: ${error.message}`
            } finally {
              isConverting.value = false
              audioChunks.value = []
            }
          }

          mediaRecorder.value.start(1000) // 每1秒分割数据
          isRecording.value = true
          errorMessage.value = ''
          startRecordTimer()
          lastRecordDuration.value = 0
        } catch (error) {
          errorMessage.value = `麦克风访问失败: ${error.message}`
        }
      } else {
        mediaRecorder.value?.stop()
        mediaRecorder.value?.stream.getTracks().forEach(track => track.stop())
        isRecording.value = false
        stopRecordTimer()
      }
    }

    // 录音计时
    function startRecordTimer() {
      recordElapsed.value = 0
      clearInterval(recordTimer)
      recordTimer = setInterval(() => {
        recordElapsed.value++
      }, 1000)
    }
    function stopRecordTimer() {
      clearInterval(recordTimer)
      recordTimer = null
    }

    // 翻译逻辑
    async function translateResult() {
      if (!finalResult.value) return
      isTranslating.value = true
      const text = finalResult.value
      try {
        const res = await axios.post('http://localhost:8000/translate', { text, to_lang: targetLang.value })
        translatedText.value = res.data.translated + `（${targetLang.value}）`
      } catch (e) {
        translatedText.value = '翻译失败'
      } finally {
        isTranslating.value = false
      }
    }

    // 初始化连接
    initWebSocket()

    // 清理资源
    onUnmounted(() => {
      if (ws.value) ws.value.close()
      if (audioContext) audioContext.close()
      if (animationFrame) cancelAnimationFrame(animationFrame)
      stopRecordTimer()
    })

    return {
      isRecording,
      isLoading,
      isConverting,
      errorMessage,
      convertProgress,
      connectionStatus,
      finalResult,
      translatedText,
      isTranslating,
      recordElapsed,
      lastRecordDuration,
      canvas,
      toggleRecording,
      translateResult,
      langOptions,
      targetLang
    }
  }
}
</script>

<style scoped>
.upload-center-wrapper {
  min-height: calc(100vh - 100px);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  background: #f3f4f6;
  padding: 2rem 1rem 2rem 1rem;
  overflow-y: auto;
}
.upload-card {
  width: 100%;
  max-width: 720px;
  background: #fff;
  border-radius: 18px;
  box-shadow: 0 4px 24px 0 rgba(0,0,0,0.08);
  padding: 2.2rem 2.5rem 1.2rem 2.5rem;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  align-items: center;
  margin-bottom: 0;
}
.center-row {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 1rem;
}
.submit-button,
.translate-button {
  transition: all 0.3s ease;
  cursor: pointer;
  border: none;
  border-radius: 8px;
  font-weight: 500;
}
.submit-button {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 24px;
  background: #4361ee;
  color: white;
  font-size: 1rem;
  min-width: 120px;
  min-height: 40px;
  position: relative;
}
/* 录音中时按钮为绿色 */
.submit-button.loading {
  background: #22c55e;
}
.submit-button .spinner {
  width: 18px;
  height: 18px;
  margin-right: 6px;
  animation: spin 1s linear infinite;
  vertical-align: middle;
}
@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
.translate-button {
  padding: 10px 28px;
  background: #f59e42;
  color: #fff;
  font-size: 1rem;
  margin-top: 0.5rem;
}
.translate-button:disabled {
  background: #fde68a;
  color: #b45309;
  cursor: not-allowed;
}
.status-message {
  padding: 1rem;
  border-radius: 8px;
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  justify-content: center;
}
.status-message.success { background: #dcfce7; color: #166534; }
.status-message.error   { background: #fee2e2; color: #b91c1c; }
.status-message.info    { background: #e0f2fe; color: #0369a1; }
.visualizer {
  margin-top: 1rem;
  background: #f8fafc; /* 与卡片背景一致 */
  border-radius: 4px;
  overflow: hidden;
}
canvas {
  width: 100%;
  height: 100px;
}
.result-container {
  width: 100%;
  padding: 2.5rem 2rem;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.result-header h3 { margin: 0 0 1rem; color: #1e293b; }
.result-details-pair {
  display: flex;
  flex-direction: row;
  gap: 3rem;
  width: 100%;
  justify-content: center;
  margin-top: 0.5rem;
}
.detail-block {
  background: #fff;
  border: 1px solid #e2e8f0;
  border-radius: 6px;
  padding: 1.2rem 1.5rem;
  min-width: 260px;
  max-width: 480px;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: flex-start;
  font-size: 1.08rem;
}
.detail-label { color: #64748b; font-weight: 500; }
.detail-value, .translated-value { color: #1e293b; font-family: monospace; word-break: break-all; }
.translated-value { color: #2563eb; font-weight: 500; }
.scrollable-text {
  max-height: 240px;
  overflow-y: auto;
  word-break: break-all;
  padding-right: 4px;
}
@media (max-width: 900px) {
  .upload-card {
    max-width: 99vw;
    padding: 1.2rem 0.5rem;
  }
  .result-details-pair {
    flex-direction: column;
    gap: 1rem;
    align-items: stretch;
  }
  .detail-block {
    min-width: auto;
    max-width: none;
  }
}

@media (max-width: 768px) {
  .upload-center-wrapper {
    padding: 1rem 0.5rem;
  }
  .upload-card {
    padding: 1rem;
  }
  .result-container {
    padding: 1.5rem 1rem;
  }
  .scrollable-text {
    max-height: 180px;
  }
}

@media (max-height: 600px) {
  .upload-center-wrapper {
    padding: 1rem 0.5rem;
  }
  .upload-card {
    padding: 1rem;
    gap: 1rem;
  }
  .result-container {
    padding: 1rem;
  }
  .scrollable-text {
    max-height: 120px;
  }
}
</style>